#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
基于Python+LVGL的汽车仪表盘图形界面
支持编译为exe文件，双击运行

功能特性：
- 真实的图形界面显示
- 实时仪表盘动画
- 鼠标交互支持
- 可编译为独立exe
"""

import sys
import time
import math
import random
import threading
from dataclasses import dataclass
from typing import Optional

try:
    import lvgl as lv
    import SDL2 as sdl2
    print("✅ 成功导入LVGL和SDL2")
except ImportError as e:
    print(f"❌ 导入失败: {e}")
    print("请安装依赖: pip install lvgl pygame")
    sys.exit(1)

# 配置常量
@dataclass
class Config:
    SCREEN_WIDTH: int = 800
    SCREEN_HEIGHT: int = 600
    MAX_SPEED: int = 220
    UPDATE_INTERVAL: float = 0.05  # 50ms
    FPS: int = 30

config = Config()

class VehicleData:
    """车辆数据模型"""
    def __init__(self):
        self.current_speed = 0
        self.target_speed = 60
        self.current_rpm = 800
        self.current_gear = 1
        self.fuel_level = 85
        self.engine_temp = 90
        self.is_running = True
        self.odometer = 123456  # 里程表
        
    def update(self):
        """更新车辆数据"""
        # 平滑速度变化
        if self.current_speed < self.target_speed:
            self.current_speed = min(self.current_speed + 2, self.target_speed)
        elif self.current_speed > self.target_speed:
            self.current_speed = max(self.current_speed - 2, self.target_speed)
        
        # 计算转速
        self.current_rpm = 800 + (self.current_speed * 25)
        if self.current_rpm > 7000:
            self.current_rpm = 7000
        
        # 计算档位
        if self.current_speed == 0:
            self.current_gear = 0  # P档
        elif self.current_speed < 20:
            self.current_gear = 1
        elif self.current_speed < 40:
            self.current_gear = 2
        elif self.current_speed < 60:
            self.current_gear = 3
        elif self.current_speed < 80:
            self.current_gear = 4
        else:
            self.current_gear = 5
        
        # 模拟引擎温度
        self.engine_temp = 85 + (self.current_speed * 0.3)
        if self.engine_temp > 120:
            self.engine_temp = 120

class Dashboard:
    """仪表盘界面类"""
    
    def __init__(self):
        self.vehicle = VehicleData()
        self.screen = None
        self.speed_arc = None
        self.speed_label = None
        self.rpm_arc = None
        self.rpm_label = None
        self.gear_label = None
        self.fuel_bar = None
        self.temp_bar = None
        self.info_label = None
        
        # 初始化LVGL
        self.init_lvgl()
        
        # 创建界面
        self.create_ui()
        
        # 启动数据更新线程
        self.start_update_thread()
    
    def init_lvgl(self):
        """初始化LVGL显示系统"""
        print("🖥️ 初始化LVGL显示系统...")
        
        # 初始化LVGL
        lv.init()
        
        # 初始化SDL2显示器
        sdl2.init()
        
        # 创建显示器
        disp_buf1 = lv.disp_draw_buf_t()
        buf1_1 = bytearray(config.SCREEN_WIDTH * 100 * 4)  # 4 bytes per pixel
        disp_buf1.init(buf1_1, None, len(buf1_1) // 4)
        
        disp_drv = lv.disp_drv_t()
        disp_drv.init()
        disp_drv.draw_buf = disp_buf1
        disp_drv.flush_cb = self.disp_flush
        disp_drv.hor_res = config.SCREEN_WIDTH
        disp_drv.ver_res = config.SCREEN_HEIGHT
        disp_drv.register()
        
        # 创建输入设备
        indev_drv = lv.indev_drv_t()
        indev_drv.init()
        indev_drv.type = lv.INDEV_TYPE.POINTER
        indev_drv.read_cb = self.mouse_read
        indev_drv.register()
        
        print("✅ LVGL显示系统初始化完成")
    
    def disp_flush(self, disp_drv, area, color_p):
        """显示刷新回调"""
        # SDL2显示更新逻辑
        # 这里简化处理，实际应该调用SDL2的渲染函数
        pass
    
    def mouse_read(self, indev_drv, data):
        """鼠标读取回调"""
        # 简化的鼠标处理
        data.state = lv.INDEV_STATE.REL
        return False
    
    def create_ui(self):
        """创建用户界面"""
        print("🎛️ 创建仪表盘界面...")
        
        # 获取活动屏幕
        self.screen = lv.scr_act()
        
        # 设置背景颜色
        self.screen.set_style_bg_color(lv.color_make(0x10, 0x10, 0x20), 0)
        
        # 创建标题
        title = lv.label(self.screen)
        title.set_text("🚗 Python+LVGL 汽车仪表盘")
        title.set_style_text_color(lv.color_white(), 0)
        title.set_style_text_font(lv.font_montserrat_20, 0)
        title.align(lv.ALIGN.TOP_MID, 0, 10)
        
        # 创建速度表
        self.create_speedometer()
        
        # 创建转速表
        self.create_rpm_gauge()
        
        # 创建信息面板
        self.create_info_panel()
        
        # 创建燃油和温度指示器
        self.create_status_bars()
        
        print("✅ 界面创建完成")
    
    def create_speedometer(self):
        """创建速度表"""
        # 速度弧形指示器
        self.speed_arc = lv.arc(self.screen)
        self.speed_arc.set_size(250, 250)
        self.speed_arc.set_pos(50, 80)
        self.speed_arc.set_range(0, config.MAX_SPEED)
        self.speed_arc.set_value(0)
        self.speed_arc.set_bg_angles(135, 45)
        self.speed_arc.set_style_arc_color(lv.color_make(0x00, 0x80, 0xFF), lv.PART.INDICATOR)
        
        # 速度标签
        self.speed_label = lv.label(self.screen)
        self.speed_label.set_text("0")
        self.speed_label.set_style_text_font(lv.font_montserrat_48, 0)
        self.speed_label.set_style_text_color(lv.color_white(), 0)
        self.speed_label.align_to(self.speed_arc, lv.ALIGN.CENTER, 0, 0)
        
        # 速度单位标签
        speed_unit = lv.label(self.screen)
        speed_unit.set_text("km/h")
        speed_unit.set_style_text_color(lv.color_make(0x80, 0x80, 0x80), 0)
        speed_unit.align_to(self.speed_label, lv.ALIGN.OUT_BOTTOM_MID, 0, 5)
    
    def create_rpm_gauge(self):
        """创建转速表"""
        # 转速弧形指示器
        self.rpm_arc = lv.arc(self.screen)
        self.rpm_arc.set_size(200, 200)
        self.rpm_arc.set_pos(500, 100)
        self.rpm_arc.set_range(0, 8000)
        self.rpm_arc.set_value(800)
        self.rpm_arc.set_bg_angles(135, 45)
        self.rpm_arc.set_style_arc_color(lv.color_make(0xFF, 0x80, 0x00), lv.PART.INDICATOR)
        
        # 转速标签
        self.rpm_label = lv.label(self.screen)
        self.rpm_label.set_text("800")
        self.rpm_label.set_style_text_font(lv.font_montserrat_24, 0)
        self.rpm_label.set_style_text_color(lv.color_white(), 0)
        self.rpm_label.align_to(self.rpm_arc, lv.ALIGN.CENTER, 0, -10)
        
        # 转速单位标签
        rpm_unit = lv.label(self.screen)
        rpm_unit.set_text("RPM")
        rpm_unit.set_style_text_color(lv.color_make(0x80, 0x80, 0x80), 0)
        rpm_unit.align_to(self.rpm_label, lv.ALIGN.OUT_BOTTOM_MID, 0, 5)
    
    def create_info_panel(self):
        """创建信息面板"""
        # 档位显示
        gear_container = lv.obj(self.screen)
        gear_container.set_size(100, 100)
        gear_container.set_pos(350, 150)
        gear_container.set_style_bg_color(lv.color_make(0x20, 0x20, 0x30), 0)
        gear_container.set_style_border_width(2, 0)
        gear_container.set_style_border_color(lv.color_make(0x40, 0x40, 0x50), 0)
        gear_container.set_style_radius(10, 0)
        
        gear_title = lv.label(gear_container)
        gear_title.set_text("档位")
        gear_title.set_style_text_color(lv.color_make(0x80, 0x80, 0x80), 0)
        gear_title.align(lv.ALIGN.TOP_MID, 0, 5)
        
        self.gear_label = lv.label(gear_container)
        self.gear_label.set_text("P")
        self.gear_label.set_style_text_font(lv.font_montserrat_32, 0)
        self.gear_label.set_style_text_color(lv.color_white(), 0)
        self.gear_label.align(lv.ALIGN.CENTER, 0, 5)
        
        # 里程表
        self.info_label = lv.label(self.screen)
        self.info_label.set_text("里程: 123456 km")
        self.info_label.set_style_text_color(lv.color_white(), 0)
        self.info_label.set_pos(50, 400)
    
    def create_status_bars(self):
        """创建状态指示条"""
        # 燃油指示器
        fuel_title = lv.label(self.screen)
        fuel_title.set_text("燃油")
        fuel_title.set_style_text_color(lv.color_white(), 0)
        fuel_title.set_pos(500, 350)
        
        self.fuel_bar = lv.bar(self.screen)
        self.fuel_bar.set_size(200, 20)
        self.fuel_bar.set_pos(500, 370)
        self.fuel_bar.set_range(0, 100)
        self.fuel_bar.set_value(85, lv.ANIM.OFF)
        self.fuel_bar.set_style_bg_color(lv.color_make(0x40, 0x40, 0x40), lv.PART.MAIN)
        self.fuel_bar.set_style_bg_color(lv.color_make(0x00, 0xFF, 0x00), lv.PART.INDICATOR)
        
        # 温度指示器
        temp_title = lv.label(self.screen)
        temp_title.set_text("水温")
        temp_title.set_style_text_color(lv.color_white(), 0)
        temp_title.set_pos(500, 420)
        
        self.temp_bar = lv.bar(self.screen)
        self.temp_bar.set_size(200, 20)
        self.temp_bar.set_pos(500, 440)
        self.temp_bar.set_range(0, 120)
        self.temp_bar.set_value(90, lv.ANIM.OFF)
        self.temp_bar.set_style_bg_color(lv.color_make(0x40, 0x40, 0x40), lv.PART.MAIN)
        self.temp_bar.set_style_bg_color(lv.color_make(0xFF, 0x80, 0x00), lv.PART.INDICATOR)
    
    def update_ui(self):
        """更新界面显示"""
        # 更新速度
        self.speed_arc.set_value(self.vehicle.current_speed)
        self.speed_label.set_text(str(self.vehicle.current_speed))
        
        # 更新转速
        self.rpm_arc.set_value(self.vehicle.current_rpm)
        self.rpm_label.set_text(str(self.vehicle.current_rpm))
        
        # 更新档位
        if self.vehicle.current_gear == 0:
            self.gear_label.set_text("P")
        else:
            self.gear_label.set_text(str(self.vehicle.current_gear))
        
        # 更新燃油
        self.fuel_bar.set_value(self.vehicle.fuel_level, lv.ANIM.OFF)
        
        # 更新温度
        self.temp_bar.set_value(int(self.vehicle.engine_temp), lv.ANIM.OFF)
        
        # 更新信息
        self.info_label.set_text(f"里程: {self.vehicle.odometer} km | 温度: {self.vehicle.engine_temp:.1f}°C")
    
    def simulate_driving(self):
        """模拟驾驶行为"""
        # 随机改变目标速度
        if random.randint(1, 100) == 1:  # 1%概率改变
            self.vehicle.target_speed = random.randint(0, config.MAX_SPEED)
            print(f"🎯 新目标速度: {self.vehicle.target_speed} km/h")
    
    def start_update_thread(self):
        """启动数据更新线程"""
        def update_loop():
            while self.vehicle.is_running:
                try:
                    # 更新车辆数据
                    self.vehicle.update()
                    
                    # 模拟驾驶
                    self.simulate_driving()
                    
                    # 更新界面
                    self.update_ui()
                    
                    # 处理LVGL任务
                    lv.task_handler()
                    
                    time.sleep(config.UPDATE_INTERVAL)
                    
                except Exception as e:
                    print(f"❌ 更新线程错误: {e}")
                    break
        
        update_thread = threading.Thread(target=update_loop, daemon=True)
        update_thread.start()
        print("🔄 数据更新线程已启动")
    
    def run(self):
        """运行主循环"""
        print("🚗 启动Python+LVGL仪表盘...")
        print("按 Ctrl+C 退出程序")
        
        try:
            while self.vehicle.is_running:
                # 处理SDL2事件
                sdl2.pump_events()
                
                # 处理LVGL任务
                lv.task_handler()
                
                # 控制帧率
                time.sleep(1.0 / config.FPS)
                
        except KeyboardInterrupt:
            print("\n👋 程序退出")
            self.vehicle.is_running = False

def main():
    """主函数"""
    print("═══════════════════════════════════════")
    print("🐍 Python+LVGL 汽车仪表盘")
    print("═══════════════════════════════════════")
    
    try:
        # 创建仪表盘应用
        dashboard = Dashboard()
        
        # 运行应用
        dashboard.run()
        
    except Exception as e:
        print(f"❌ 程序运行错误: {e}")
        import traceback
        traceback.print_exc()
        return 1
    
    return 0

if __name__ == "__main__":
    sys.exit(main())